//+------------------------------------------------------------------+
//|                                             SimpleMartingale.mq4 |
//|                                  Copyright 2023, MetaQuotes Ltd |
//|                                        https://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd"
#property link      "https://www.metaquotes.net"
#property version   "1.00"
#property strict

//--- 输入参数
input double InitialLots = 0.01;        // 初始开仓手数
input double AddLots1 = 0.02;           // 第一次补仓手数
input double AddLots2 = 0.04;           // 第二次补仓手数
input double AddLots3 = 0.06;           // 第三次补仓手数
input double AddLots4 = 0.08;           // 第四次补仓手数
input double AddLots5 = 0.1;           // 第五次补仓手数
input int TakeProfitPoints = 10;       // 止盈点数
input double RiskThreshold = 5.0;      // 风控阈值（百分比）
input int NewDayOpenTimeMinutes = 5;   // 日K线开盘后允许开仓的分钟数（00:00-00:04，共5分钟）
input int MagicNumber = 20250812;      // 魔术码（用于识别本策略的订单）

//--- 全局变量
// 删除g_isTrading冗余变量，直接通过HasOpenPositions()判断策略状态
bool g_isBuyDirection = false;         // 当前交易方向（true为买入，false为卖出）
int g_tradeCount = 0;                  // 当前交易次数（包括首次开仓和补仓）
double g_totalLots = 0.0;              // 当前总持仓量
// 删除未使用的时间变量
bool g_isRiskStopped = false;          // 是否因风控而停止交易
// 删除冗余的状态标志，直接通过HasAnyTradesToday()检查

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // 验证输入参数
   if(InitialLots <= 0 || AddLots1 <= 0 || AddLots2 <= 0 || AddLots3 <= 0 || AddLots4 <= 0 || AddLots5 <= 0)
   {
      Print("错误：手数必须大于0");
      return INIT_PARAMETERS_INCORRECT;
   }
   
   if(TakeProfitPoints <= 0)
   {
      Print("错误：止盈点数必须大于0");
      return INIT_PARAMETERS_INCORRECT;
   }
   
   if(RiskThreshold <= 0 || RiskThreshold > 100)
   {
      Print("错误：风控阈值必须在0-100之间");
      return INIT_PARAMETERS_INCORRECT;
   }
   
   // 初始化全局变量
   g_isBuyDirection = false;
   g_tradeCount = 0;
   g_totalLots = 0.0;
   // 删除未使用的时间变量初始化
   g_isRiskStopped = false;
   
   // 简化初始化：检查今日交易情况
   if(HasAnyTradesToday())
   {
      Print("初始化时检测到今日已有交易记录，今日将不再开仓");
   }
   
   // 检查交易权限和环境
   Print("=======================================");
   Print("开盘马丁策略EA初始化开始");
   
   // 执行完整的环境检查
   bool environmentOK = CheckTradingEnvironment();
   
   if(environmentOK)
   {
      Print("开盘马丁策略EA初始化成功");
   }
   else
   {
      Print("开盘马丁策略EA初始化完成，但存在环境问题，请检查上述提示");
   }
   Print("初始手数: ", InitialLots);
   Print("补仓手数: ", AddLots1, ", ", AddLots2, ", ", AddLots3, ", ", AddLots4, ", ", AddLots5);
   Print("止盈点数: ", TakeProfitPoints);
   Print("风控阈值: ", RiskThreshold, "%");
   Print("开仓时间窗口: 日K线开盘后", NewDayOpenTimeMinutes, "分钟内");
   Print("交易规则: 每日K线开盘后", NewDayOpenTimeMinutes, "分钟内开仓，每天只交易一轮");
   Print("魔术码: ", MagicNumber, " (用于区分其他策略订单)");
   Print("今日交易检查: ", (HasAnyTradesToday() ? "检测到今日交易，今日不再开仓" : "未检测到今日交易"));
   
   // 显示当前状态
   if(HasAnyTradesToday())
   {
      Print("当前状态: 检测到今日交易，今日不再开仓，等待下一个交易日");
   }
   else if(IsWithinOpenTimeWindow())
   {
      Print("当前状态: 在开仓时间窗口内，等待开仓");
   }
   else
   {
      Print("当前状态: 已错过今日开仓时间窗口，等待下一个交易日");
   }
   Print("=======================================");
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // 输出终止信息
   Print("开盘马丁策略EA终止，原因代码: ", reason);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // 检查EA交易权限
   if(!IsTradeAllowed())
   {
      // 每100个tick输出一次状态，避免日志过多
      if(GetTickCount() % 100 == 0)
      {
         Print("当前状态: EA交易被禁用，请在MT4中启用'自动交易'按钮");
      }
      return; // 如果EA交易被禁用，停止所有操作
   }
   
   // 检查专家顾问是否被启用
   if(!IsExpertEnabled())
   {
      // 每100个tick输出一次状态，避免日志过多
      if(GetTickCount() % 100 == 0)
      {
         Print("当前状态: 专家顾问被禁用，请检查EA设置");
      }
      return; // 如果专家顾问被禁用，停止所有操作
   }
   
   // 检查是否允许实时交易
   if(!IsTradeContextBusy() && !IsConnected())
   {
      // 每100个tick输出一次状态，避免日志过多
      if(GetTickCount() % 100 == 0)
      {
         Print("当前状态: 与交易服务器连接中断，请检查网络连接");
      }
      return; // 如果与服务器连接中断，停止所有操作
   }
   
   
   // 检查风险水平
   if(CheckRisk())
   {
      Print("=======================================");
      Print("警告：触发风控机制，账户浮动亏损超过", RiskThreshold, "%");
      Print("状态变更: 正常交易 -> 风控强制平仓");
      ForceCloseAllPositions();
      g_isRiskStopped = true;
      // 删除g_tradedToday，风控平仓后自动通过HasAnyTradesToday()检查
      Print("当前状态: 风控已触发，EA已停止交易，请手动重置EA");
      Print("=======================================");
      return;
   }
   
   // 极简开仓判断：时间窗口内 + 今日无交易（已包含持仓检查）
   bool inTimeWindow = IsWithinOpenTimeWindow();
   bool hasTraded = HasAnyTradesToday();
   bool canOpenPosition = inTimeWindow && !hasTraded;
   
   // 如果满足开仓条件，则开仓
   if(canOpenPosition)
   {
      Print("=======================================");
      Print("状态变更: 等待开仓 -> 准备开仓");
      
      // 获取前一日趋势方向
      g_isBuyDirection = GetPreviousDayTrend();
      Print("前一日趋势方向: ", (g_isBuyDirection ? "上涨，准备买入" : "下跌，准备卖出"));
      
      // 开仓
      if(OpenPosition(g_isBuyDirection, InitialLots))
      {
         g_tradeCount = 1;
         g_totalLots = InitialLots;
         // 删除g_tradedToday，直接通过HasAnyTradesToday()检查
         Print("首次开仓成功，方向: ", (g_isBuyDirection ? "买入" : "卖出"), "，手数: ", InitialLots);
         Print("当前状态: 已开仓，等待止盈或补仓");
         Print("=======================================");
      }
      else
      {
         Print("开仓失败，将在下个交易信号尝试");
         Print("当前状态: 开仓失败，继续等待");
         Print("=======================================");
      }
   }
   
   // 如果已有持仓，检查是否需要平仓或补仓
   if(HasOpenPositions())
   {
      // 计算当前盈亏点数
      double profitPoints = CalculateProfitPoints();
      
      // 每50个tick输出一次当前状态，避免日志过多
      if(GetTickCount() % 50 == 0)
      {
         Print("当前状态: 持仓中，交易次数: ", g_tradeCount, "，总手数: ", g_totalLots, 
               "，当前盈亏点数: ", DoubleToString(profitPoints, 1), 
               "，止盈目标: ", TakeProfitPoints);
      }
      
      // 如果达到止盈点数，平仓
      if(profitPoints >= TakeProfitPoints)
      {
         Print("=======================================");
         Print("状态变更: 持仓中 -> 达到止盈条件");
         Print("当前盈亏点数: ", DoubleToString(profitPoints, 1), " >= 止盈点数: ", TakeProfitPoints);
         
         // 计算当前盈利金额
         double profitMoney = CalculateTotalProfitMoney();
         
         if(CloseAllPositions())
         {
            Print("止盈平仓成功，盈利点数: ", DoubleToString(profitPoints, 1), "，盈利金额: ", DoubleToString(profitMoney, 2), " ", AccountCurrency());
            ResetTradeStatus();
            // 删除复杂的状态管理，平仓后自动通过HasAnyTradesToday()检查
            Print("当前状态: 今日交易已完成，等待下一个交易日");
            Print("=======================================");
         }
         else
         {
            Print("止盈平仓失败，将继续尝试");
            Print("=======================================");
         }
      }
      // 如果亏损且未达到最大交易次数，考虑补仓
      else if(profitPoints < 0 && g_tradeCount < 6)
      {
         // 根据当前交易次数确定补仓手数
         double addLots = 0.0;
         switch(g_tradeCount)
         {
            case 1: addLots = AddLots1; break;
            case 2: addLots = AddLots2; break;
            case 3: addLots = AddLots3; break;
            case 4: addLots = AddLots4; break;
            case 5: addLots = AddLots5; break;
            default: addLots = 0.0; break;
         }
         
         // 补仓
         if(addLots > 0 && AddPosition(g_isBuyDirection, addLots))
         {
            Print("=======================================");
            Print("状态变更: 持仓中 -> 执行补仓");
            g_tradeCount++;
            g_totalLots += addLots;
            Print("补仓成功，第", g_tradeCount-1, "次补仓，方向: ", (g_isBuyDirection ? "买入" : "卖出"), "，手数: ", addLots, "，总手数: ", g_totalLots);
            Print("当前状态: 已补仓", g_tradeCount-1, "次，等待止盈或继续补仓");
            Print("=======================================");
         }
      }
      else if(g_tradeCount >= 6 && profitPoints < 0)
      {
         // 使用基于时间的控制方式减少日志输出
         datetime currentTime = TimeCurrent();
         int currentMinute = TimeMinute(currentTime);
         int currentSecond = TimeSeconds(currentTime);
         
         // 每3分钟输出一次状态信息
         if(currentMinute % 3 == 0 && currentSecond < 10)
         {
            Print("当前状态: 已达到最大补仓次数，等待行情回调至止盈点");
         }
      }
   }
   else if(!HasOpenPositions())
   {
      // 智能状态输出：根据不同状态使用不同频率和逻辑
      datetime currentTime = TimeCurrent();
      int currentMinute = TimeMinute(currentTime);
      int currentSecond = TimeSeconds(currentTime);
      
      // 获取当前状态
      bool inTimeWindow = IsWithinOpenTimeWindow();
      bool hasTraded = HasAnyTradesToday();
      
      if(hasTraded)
      {
         // 今日已交易：每30分钟输出一次即可
         // if(currentMinute % 30 == 0 && currentSecond < 10)
         // {
         //    Print("当前状态: 今日交易已完成，等待下一个交易日");
         // }
      }
      else if(inTimeWindow)
      {
         // 在时间窗口内但未交易：每分钟输出一次，显示详细时间信息
         if(currentSecond < 5)  // 每分钟前5秒输出
         {
            datetime serverTime = TimeCurrent();
            int serverHour = TimeHour(serverTime);
            int serverMinute = TimeMinute(serverTime);
            int remainingMinutes = NewDayOpenTimeMinutes - serverMinute - 1;
            Print("当前状态: 在开仓时间窗口内");
            Print("  当前服务器时间: ", TimeToStr(serverTime, TIME_DATE|TIME_MINUTES), 
                  " (", serverHour, ":", (serverMinute < 10 ? "0" : ""), serverMinute, ")");
            Print("  开仓时间窗口: 00:00-00:", (NewDayOpenTimeMinutes-1), 
                  ", 剩余时间: ", remainingMinutes, "分钟");
         }
      }
      else
      {
         // 错过时间窗口：每天只输出一次
         static datetime lastMissedWindowAlert = 0;
         datetime todayStart = iTime(Symbol(), PERIOD_D1, 0);
         
         if(todayStart != lastMissedWindowAlert)
         {
            Print("当前状态: 已错过今日开仓时间窗口，等待下一个交易日");
            lastMissedWindowAlert = todayStart;
         }
      }
   }
}

// 删除未使用的IsNewDay函数，时间检查已简化为直接的K线时间判断

//+------------------------------------------------------------------+
//| 获取前一日K线趋势方向                                             |
//+------------------------------------------------------------------+
bool GetPreviousDayTrend()
{
   // 获取前一日K线的开盘价和收盘价
   double prevOpen = iOpen(Symbol(), PERIOD_D1, 1);
   double prevClose = iClose(Symbol(), PERIOD_D1, 1);
   
   // 如果收盘价大于开盘价，则为上涨趋势，否则为下跌趋势
   return (prevClose > prevOpen);
}

//+------------------------------------------------------------------+
//| 计算当前持仓的盈亏点数                                            |
//+------------------------------------------------------------------+
double CalculateProfitPoints()
{
   double totalProfit = 0.0;
   double totalLots = 0.0;
   
   // 遍历所有持仓，计算加权平均盈亏点数
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && (OrderType() == OP_BUY || OrderType() == OP_SELL))
         {
            double pointsProfit = 0.0;
            
            // 计算点数盈亏
            if(OrderType() == OP_BUY)
            {
               pointsProfit = (Bid - OrderOpenPrice()) / Point;
            }
            else if(OrderType() == OP_SELL)
            {
               pointsProfit = (OrderOpenPrice() - Ask) / Point;
            }
            
            // 累加加权盈亏
            totalProfit += pointsProfit * OrderLots();
            totalLots += OrderLots();
         }
      }
   }
   
   // 计算加权平均盈亏点数
   if(totalLots > 0)
   {
      return totalProfit / totalLots;
   }
   
   return 0.0;
}

//+------------------------------------------------------------------+
//| 计算当前持仓的总盈亏金额                                          |
//+------------------------------------------------------------------+
double CalculateTotalProfitMoney()
{
   double totalProfitMoney = 0.0;
   
   // 遍历所有持仓，计算总盈亏金额
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && (OrderType() == OP_BUY || OrderType() == OP_SELL))
         {
            // 累加订单盈亏金额
            totalProfitMoney += OrderProfit() + OrderSwap() + OrderCommission();
         }
      }
   }
   
   return totalProfitMoney;
}

//+------------------------------------------------------------------+
//| 检查是否有持仓                                                    |
//+------------------------------------------------------------------+
bool HasOpenPositions()
{
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && (OrderType() == OP_BUY || OrderType() == OP_SELL))
         {
            return true;
         }
      }
   }
   
   return false;
}

//+------------------------------------------------------------------+
//| 开仓函数                                                          |
//+------------------------------------------------------------------+
bool OpenPosition(bool isBuy, double lots)
{
   // 设置订单参数
   string symbol = Symbol();
   int cmd = isBuy ? OP_BUY : OP_SELL;
   double price = isBuy ? Ask : Bid;
   double sl = 0; // 本策略不设置止损
   double tp = 0; // 本策略不设置止盈，通过代码逻辑实现
   string comment = "开盘马丁策略-首次开仓";
   
   // 发送订单
   int ticket = OrderSend(symbol, cmd, lots, price, 3, sl, tp, comment, MagicNumber, 0, isBuy ? clrBlue : clrRed);
   
   // 检查订单是否成功
   if(ticket < 0)
   {
      int error = GetLastError();
      Print("开仓失败，错误代码: ", error, "，错误描述: ", ErrorDescription(error));
      
      // 针对常见错误提供解决建议
      switch(error)
      {
         case 4109: // ERR_TRADE_NOT_ALLOWED
            Print("解决建议: 请检查以下设置:");
            Print("1. 确保MT4中'自动交易'按钮已启用（绿色状态）");
            Print("2. 确保EA设置中允许实时交易");
            Print("3. 检查经纪商是否允许EA交易");
            break;
         case 134: // ERR_NOT_ENOUGH_MONEY
            Print("解决建议: 账户资金不足，请充值或减少交易手数");
            break;
         case 130: // ERR_INVALID_STOPS
            Print("解决建议: 价格无效，可能是市场关闭或价格异常");
            break;
         case 136: // ERR_OFF_QUOTES
            Print("解决建议: 价格过期，请等待新的报价");
            break;
         case 137: // ERR_BROKER_BUSY
            Print("解决建议: 经纪商服务器繁忙，请稍后重试");
            break;
         case 138: // ERR_REQUOTE
            Print("解决建议: 价格重新报价，请等待新的价格");
            break;
         default:
            Print("解决建议: 请检查网络连接和交易服务器状态");
            break;
      }
      
      return false;
   }
   
   return true;
}

//+------------------------------------------------------------------+
//| 补仓函数                                                          |
//+------------------------------------------------------------------+
bool AddPosition(bool isBuy, double lots)
{
   // 设置订单参数
   string symbol = Symbol();
   int cmd = isBuy ? OP_BUY : OP_SELL;
   double price = isBuy ? Ask : Bid;
   double sl = 0; // 本策略不设置止损
   double tp = 0; // 本策略不设置止盈，通过代码逻辑实现
   string comment = "开盘马丁策略-补仓" + IntegerToString(g_tradeCount);
   
   // 发送订单
   int ticket = OrderSend(symbol, cmd, lots, price, 3, sl, tp, comment, MagicNumber, 0, isBuy ? clrBlue : clrRed);
   
   // 检查订单是否成功
   if(ticket < 0)
   {
      int error = GetLastError();
      Print("补仓失败，错误代码: ", error, "，错误描述: ", ErrorDescription(error));
      
      // 针对常见错误提供解决建议
      switch(error)
      {
         case 4109: // ERR_TRADE_NOT_ALLOWED
            Print("解决建议: 请检查以下设置:");
            Print("1. 确保MT4中'自动交易'按钮已启用（绿色状态）");
            Print("2. 确保EA设置中允许实时交易");
            Print("3. 检查经纪商是否允许EA交易");
            break;
         case 134: // ERR_NOT_ENOUGH_MONEY
            Print("解决建议: 账户资金不足，请充值或减少交易手数");
            break;
         case 130: // ERR_INVALID_STOPS
            Print("解决建议: 价格无效，可能是市场关闭或价格异常");
            break;
         case 136: // ERR_OFF_QUOTES
            Print("解决建议: 价格过期，请等待新的报价");
            break;
         case 137: // ERR_BROKER_BUSY
            Print("解决建议: 经纪商服务器繁忙，请稍后重试");
            break;
         case 138: // ERR_REQUOTE
            Print("解决建议: 价格重新报价，请等待新的价格");
            break;
         default:
            Print("解决建议: 请检查网络连接和交易服务器状态");
            break;
      }
      
      return false;
   }
   
   return true;
}

//+------------------------------------------------------------------+
//| 平仓所有持仓                                                      |
//+------------------------------------------------------------------+
bool CloseAllPositions()
{
   bool result = true;
   
   // 从最后一个订单开始遍历，避免因订单关闭导致的索引变化
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && (OrderType() == OP_BUY || OrderType() == OP_SELL))
         {
            // 根据订单类型确定平仓价格
            double closePrice = OrderType() == OP_BUY ? Bid : Ask;
            
            // 关闭订单
            bool closeResult = OrderClose(OrderTicket(), OrderLots(), closePrice, 3, clrWhite);
            
            // 检查平仓是否成功
            if(!closeResult)
            {
               int error = GetLastError();
               Print("平仓失败，订单号: ", OrderTicket(), "，错误代码: ", error, "，错误描述: ", ErrorDescription(error));
               result = false;
            }
         }
      }
   }
   
   return result;
}

//+------------------------------------------------------------------+
//| 强制平仓所有持仓（风控触发时使用）                                 |
//+------------------------------------------------------------------+
void ForceCloseAllPositions()
{
   Print("风控触发，强制平仓所有持仓");
   int totalOrders = OrdersTotal();
   Print("当前持仓订单数量: ", totalOrders);
   int closedOrders = 0;
   int failedOrders = 0;
   
   // 从最后一个订单开始遍历，避免因订单关闭导致的索引变化
   for(int i = totalOrders - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && (OrderType() == OP_BUY || OrderType() == OP_SELL))
         {
            // 根据订单类型确定平仓价格
            double closePrice = OrderType() == OP_BUY ? Bid : Ask;
            int ticket = OrderTicket();
            double lots = OrderLots();
            int type = OrderType();
            
            Print("尝试平仓订单 #", ticket, ", 类型: ", (type == OP_BUY ? "买入" : "卖出"), ", 手数: ", lots);
            
            // 关闭订单
            bool closeResult = OrderClose(ticket, lots, closePrice, 3, clrWhite);
            
            // 检查平仓是否成功
            if(closeResult)
            {
               closedOrders++;
               Print("订单 #", ticket, " 平仓成功");
            }
            else
            {
               failedOrders++;
               int error = GetLastError();
               Print("强制平仓失败，订单号: ", ticket, "，错误代码: ", error, "，错误描述: ", ErrorDescription(error));
            }
         }
      }
   }
   
   Print("风控平仓结果: 成功平仓 ", closedOrders, " 个订单, 失败 ", failedOrders, " 个订单");
   
   // 重置交易状态
   ResetTradeStatus();
}

//+------------------------------------------------------------------+
//| 检查风险水平                                                      |
//+------------------------------------------------------------------+
bool CheckRisk()
{
   // 计算账户浮动亏损比例
   double balance = AccountBalance();
   double equity = AccountEquity();
   double lossRatio = 0.0;
   
   if(balance > 0)
   {
      lossRatio = (balance - equity) / balance * 100.0;
   }
   
   // 如果亏损比例超过风控阈值，返回true
   return (lossRatio >= RiskThreshold);
}

//+------------------------------------------------------------------+
//| 重置交易状态                                                      |
//+------------------------------------------------------------------+
void ResetTradeStatus()
{
   Print("重置交易状态: 交易次数和总手数已重置");
   g_tradeCount = 0;
   g_totalLots = 0.0;
}

//+------------------------------------------------------------------+
//| 检查今日是否有任何交易痕迹（持仓或平仓记录）                        |
//+------------------------------------------------------------------+
bool HasAnyTradesToday()
{
   datetime todayStart = iTime(Symbol(), PERIOD_D1, 0);
   datetime tomorrowStart = todayStart + 24*60*60;
   
   // 检查当前持仓 - 有持仓说明今日已有交易
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && (OrderType() == OP_BUY || OrderType() == OP_SELL))
         {
            if(OrderOpenTime() >= todayStart && OrderOpenTime() < tomorrowStart)
            {
               return true; // 有今日持仓
            }
         }
      }
   }
   
   // 检查历史订单 - 有平仓记录说明今日已有交易
   for(int i = 0; i < OrdersHistoryTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
         {
            if(OrderOpenTime() >= todayStart && OrderOpenTime() < tomorrowStart)
            {
               return true; // 有今日平仓记录
            }
         }
      }
   }
   
   return false; // 今日无任何交易痕迹
}

// 删除不必要的复杂状态管理函数，直接使用HasAnyTradesToday()检查

//+------------------------------------------------------------------+
//| 检查交易环境是否满足要求                                          |
//+------------------------------------------------------------------+
bool CheckTradingEnvironment()
{
   bool allOK = true;
   string errorMessages = "";
   
   Print("开始检查交易环境...");
   
   // 1. 检查EA交易权限
   if(!IsTradeAllowed())
   {
      Print("❌ EA交易被禁用！");
      errorMessages += "• EA交易被禁用，请在MT4工具栏点击'自动交易'按钮启用\n";
      allOK = false;
   }
   else
   {
      Print("✓ EA交易权限检查通过");
   }
   
   // 2. 检查专家顾问是否被启用
   if(!IsExpertEnabled())
   {
      Print("❌ 专家顾问被禁用！");
      errorMessages += "• 专家顾问被禁用，请在EA属性中勾选'允许实时交易'\n";
      allOK = false;
   }
   else
   {
      Print("✓ 专家顾问权限检查通过");
   }
   
   // 3. 检查服务器连接
   if(!IsConnected())
   {
      Print("❌ 与交易服务器连接中断！");
      errorMessages += "• 服务器连接中断，请检查网络连接\n";
      allOK = false;
   }
   else
   {
      Print("✓ 交易服务器连接正常");
   }
   
   // 4. 检查交易时段
   if(!IsTradeContextBusy())
   {
      Print("✓ 交易上下文可用");
   }
   else
   {
      Print("⚠ 交易上下文繁忙，可能影响交易执行");
   }
   
   // 5. 检查账户类型
   if(AccountFreeMargin() > 0)
   {
      Print("✓ 账户可用保证金: ", DoubleToString(AccountFreeMargin(), 2), " ", AccountCurrency());
   }
   else
   {
      Print("❌ 账户可用保证金不足！");
      errorMessages += "• 账户可用保证金不足，无法进行交易\n";
      allOK = false;
   }
   
   // 6. 检查最小手数
   double minLot = MarketInfo(Symbol(), MODE_MINLOT);
   double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   if(InitialLots < minLot || InitialLots > maxLot)
   {
      Print("❌ 初始手数设置不合理！当前设置: ", InitialLots, ", 允许范围: ", minLot, "-", maxLot);
      errorMessages += "• 初始手数超出允许范围 [" + DoubleToString(minLot, 2) + "-" + DoubleToString(maxLot, 2) + "]\n";
      allOK = false;
   }
   else
   {
      Print("✓ 手数设置检查通过，允许范围: ", minLot, "-", maxLot);
   }
   
   // 7. 检查货币对交易时间
   if(MarketInfo(Symbol(), MODE_TRADEALLOWED) == 1)
   {
      Print("✓ 当前货币对允许交易: ", Symbol());
   }
   else
   {
      Print("❌ 当前货币对不允许交易: ", Symbol());
      errorMessages += "• 货币对 " + Symbol() + " 当前不允许交易，可能是非交易时段\n";
      allOK = false;
   }
   
   // 8. 检查魔术码冲突
   bool magicConflict = CheckMagicNumberConflict();
   if(magicConflict)
   {
      Print("⚠ 检测到其他EA使用相同魔术码，可能影响订单识别");
      // 不设为错误，只是警告
   }
   else
   {
      Print("✓ 魔术码检查通过: ", MagicNumber);
   }
   
   // 如果有错误，显示弹窗提醒
   if(!allOK)
   {
      string alertMessage = "开盘马丁策略 EA 环境检查失败！\n\n" + 
                           "发现以下问题：\n" + errorMessages + 
                           "\n请解决上述问题后重新加载EA。\n" +
                           "详细信息请查看终端日志。";
      
      Alert(alertMessage);
      MessageBox(alertMessage, "EA环境检查失败", MB_OK | MB_ICONWARNING);
      
      Print("=======================================");
      Print("EA环境检查失败！请解决以下问题：");
      Print(errorMessages);
      Print("=======================================");
   }
   else
   {
      Print("✓ 所有环境检查通过，EA可以正常运行");
      Print(GetOrderStatistics()); // 显示订单统计
      // Alert("开盘马丁策略 EA 初始化成功！\n所有环境检查通过，EA已准备就绪。\n魔术码: " + IntegerToString(MagicNumber));
   }
   
   return allOK;
}

//+------------------------------------------------------------------+
//| 检查魔术码冲突                                                    |
//+------------------------------------------------------------------+
bool CheckMagicNumberConflict()
{
   // 检查当前持仓中是否有其他EA使用相同魔术码
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() != Symbol() && OrderMagicNumber() == MagicNumber)
         {
            Print("发现魔术码冲突: 订单#", OrderTicket(), " 在货币对 ", OrderSymbol(), " 使用了相同魔术码 ", MagicNumber);
            return true;
         }
      }
   }
   
   // 检查历史订单中是否有其他EA使用相同魔术码（近期）
   datetime checkTime = TimeCurrent() - 24*60*60; // 检查最近24小时
   for(int i = OrdersHistoryTotal() - 1; i >= 0 && i >= OrdersHistoryTotal() - 100; i--) // 只检查最近100个订单
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
      {
         if(OrderCloseTime() >= checkTime && OrderSymbol() != Symbol() && OrderMagicNumber() == MagicNumber)
         {
            Print("发现魔术码冲突: 历史订单#", OrderTicket(), " 在货币对 ", OrderSymbol(), " 使用了相同魔术码 ", MagicNumber);
            return true;
         }
      }
   }
   
   return false;
}

//+------------------------------------------------------------------+
//| 获取本策略的订单统计信息                                          |
//+------------------------------------------------------------------+
string GetOrderStatistics()
{
   int totalOrders = 0;
   int buyOrders = 0;
   int sellOrders = 0;
   double totalLots = 0.0;
   
   // 统计当前持仓
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && (OrderType() == OP_BUY || OrderType() == OP_SELL))
         {
            totalOrders++;
            totalLots += OrderLots();
            if(OrderType() == OP_BUY) buyOrders++;
            else sellOrders++;
         }
      }
   }
   
   string stats = "持仓统计: 总订单=" + IntegerToString(totalOrders) + 
                  ", 买单=" + IntegerToString(buyOrders) + 
                  ", 卖单=" + IntegerToString(sellOrders) + 
                  ", 总手数=" + DoubleToString(totalLots, 2);
   return stats;
}

//+------------------------------------------------------------------+
//| 判断当前时间是否在日K线开盘后的允许开仓时间窗口内                  |
//+------------------------------------------------------------------+
bool IsWithinOpenTimeWindow()
{
   // 获取当前服务器时间（实时时间）
   datetime currentBarTime = TimeCurrent();
   
   // 获取今日真实开盘时间：找到今日第一条分钟K线
   datetime todayStart = iTime(Symbol(), PERIOD_D1, 0); // 日K线时间（00:00）
   datetime tomorrowStart = todayStart + 24 * 60 * 60;  // 明日00:00
   
   datetime realOpenTime = 0;
   
   // 从历史向现在查找今日第一条分钟K线（正确的查找方向）
   for(int i = 1440; i >= 0; i--) // 从1440分钟前开始向现在查找
   {
      datetime minuteBarTime = iTime(Symbol(), PERIOD_M1, i);
      
      // 如果找到今日范围内的K线，这就是最早的开盘时间
      if(minuteBarTime >= todayStart && minuteBarTime < tomorrowStart)
      {
         realOpenTime = minuteBarTime; // 找到第一条今日K线，立即记录并退出
         break; // 重要：找到最早的开盘时间后立即退出循环
      }
   }
   
   // 如果没找到今日开盘时间，返回false（今日休市）
   if(realOpenTime == 0)
   {
      static datetime lastNoOpenAlert = 0;
      if(todayStart != lastNoOpenAlert)
      {
         Print("今日休市：未找到开盘K线，不执行开仓操作");
         lastNoOpenAlert = todayStart;
      }
      return false;
   }
   
   // 计算从真实开盘时间到当前K线的时间差（秒）
   int secondsSinceOpen = (int)(currentBarTime - realOpenTime);
   
   // 将时间差转换为分钟
   int minutesSinceOpen = secondsSinceOpen / 60;
   
   // 判断是否在开仓窗口内：距离真实开盘时间小于设定的分钟数
   bool isWithinWindow = (minutesSinceOpen >= 0 && minutesSinceOpen < NewDayOpenTimeMinutes);
   
   // 增强的调试信息：输出详细的时间检查信息，方便查阅问题
   static datetime lastDebugTime = 0;
   static bool hasLoggedOpenTime = false;
   
   // 每个新K线输出一次调试信息
   if(currentBarTime != lastDebugTime)
   {
      // 首次找到开盘时间时，输出详细信息
      if(!hasLoggedOpenTime && realOpenTime > 0)
      {
         Print("=======================================");
         Print("【开盘时间检测结果】");
         Print("  交易品种: ", Symbol());
         Print("  日K线时间: ", TimeToStr(todayStart, TIME_DATE|TIME_MINUTES));
         Print("  真实开盘时间: ", TimeToStr(realOpenTime, TIME_DATE|TIME_MINUTES));
         Print("  开盘时间详情: ", TimeHour(realOpenTime), ":", 
               (TimeMinute(realOpenTime) < 10 ? "0" : ""), TimeMinute(realOpenTime));
         Print("  开仓时间窗口: 开盘后 0-", (NewDayOpenTimeMinutes-1), " 分钟 (共", NewDayOpenTimeMinutes, "分钟)");
         Print("  窗口结束时间: ", TimeToStr(realOpenTime + NewDayOpenTimeMinutes * 60, TIME_DATE|TIME_MINUTES));
         Print("=======================================");
         hasLoggedOpenTime = true;
      }
      
      // 在关键时间点输出调试信息
      bool shouldLog = false;
      string logReason = "";
      
      if(minutesSinceOpen >= 0 && minutesSinceOpen < NewDayOpenTimeMinutes)
      {
         shouldLog = true;
         logReason = "在开仓窗口内";
      }
      else if(minutesSinceOpen == NewDayOpenTimeMinutes)
      {
         shouldLog = true;
         logReason = "刚好超出开仓窗口";
      }
      else if(minutesSinceOpen > 0 && minutesSinceOpen <= NewDayOpenTimeMinutes + 10)
      {
         // 开盘后10分钟内偶尔输出，每3分钟一次
         if(minutesSinceOpen % 3 == 0)
         {
            shouldLog = true;
            logReason = "开盘后状态检查";
         }
      }
      else if(minutesSinceOpen < 0)
      {
         shouldLog = true;
         logReason = "时间异常：当前时间早于开盘时间";
      }
      
      if(shouldLog)
      {
         Print("【时间窗口检查】(", logReason, ")");
         Print("  当前服务器时间: ", TimeToStr(currentBarTime, TIME_DATE|TIME_MINUTES));
         Print("  今日开盘时间: ", TimeToStr(realOpenTime, TIME_DATE|TIME_MINUTES));
         Print("  距离开盘时间: ", minutesSinceOpen, " 分钟");
         Print("  开仓窗口设置: ", NewDayOpenTimeMinutes, " 分钟");
         
         if(minutesSinceOpen >= 0)
         {
            if(isWithinWindow)
            {
               Print("  ✓ 判断结果: 在开仓窗口内 (", minutesSinceOpen, "/", (NewDayOpenTimeMinutes-1), ")");
            }
            else
            {
               Print("  ✗ 判断结果: 不在开仓窗口内 (", minutesSinceOpen, " >= ", NewDayOpenTimeMinutes, ")");
            }
         }
         else
         {
            Print("  ⚠ 异常: 当前时间早于开盘时间 ", (-minutesSinceOpen), " 分钟");
         }
         
         // 显示当前时间详情
         int currentHour = TimeHour(currentBarTime);
         int currentMinute = TimeMinute(currentBarTime);
         Print("  当前时间详情: ", currentHour, ":", (currentMinute < 10 ? "0" : ""), currentMinute);
      }
      
      lastDebugTime = currentBarTime;
   }
   
   return isWithinWindow;
}

//+------------------------------------------------------------------+
//| 获取错误描述                                                      |
//+------------------------------------------------------------------+
string ErrorDescription(int error_code)
{
   string error_string;
   
   switch(error_code)
   {
      case 0:   error_string = "没有错误"; break;
      case 1:   error_string = "没有错误，交易操作成功"; break;
      case 2:   error_string = "一般错误"; break;
      case 3:   error_string = "无效的交易参数"; break;
      case 4:   error_string = "交易服务器繁忙"; break;
      case 5:   error_string = "客户端终端版本太旧"; break;
      case 6:   error_string = "没有连接到交易服务器"; break;
      case 7:   error_string = "没有权限"; break;
      case 8:   error_string = "请求太频繁"; break;
      case 9:   error_string = "交易操作太频繁"; break;
      case 64:  error_string = "账户被禁用"; break;
      case 65:  error_string = "无效的账户"; break;
      case 128: error_string = "交易超时"; break;
      case 129: error_string = "无效的价格"; break;
      case 130: error_string = "无效的止损"; break;
      case 131: error_string = "无效的止盈"; break;
      case 132: error_string = "市场已关闭"; break;
      case 133: error_string = "交易被禁止"; break;
      case 134: error_string = "资金不足"; break;
      case 135: error_string = "价格已改变"; break;
      case 136: error_string = "没有报价"; break;
      case 137: error_string = "经纪商很忙"; break;
      case 138: error_string = "重新报价"; break;
      case 139: error_string = "订单被锁定"; break;
      case 140: error_string = "只允许做多"; break;
      case 141: error_string = "太多请求"; break;
      case 145: error_string = "因为订单距离市场太近，修改被拒绝"; break;
      case 146: error_string = "交易上下文忙"; break;
      case 147: error_string = "过期日期在订单修改中被经纪商拒绝"; break;
      case 148: error_string = "订单被经纪商修改"; break;
      default:  error_string = "未知错误"; break;
   }
   
   return error_string;
}
//+------------------------------------------------------------------+